import sys
import builtins

__main__ = '__main__'  #defaut entrypoint

try:
    unset
except:
    unset = object()
    pdb = print
    class use:
        board = False
        lives = True
        @classmethod
        def gc(cls):
            print('15:GC N/I')

    builtins.use = use

paused = unset
pstab = {}
cycle = 1
failures = 0

#
#try:
#    import contextvars
#    setattr(builtins,'contextvars',contextvars)
#    del contextvars
#except:
#    pdb("6: contextvars module is broken")


try:
    import uasyncio as lib
except Exception as e:
    sys.print_exception(e,sys.stderr)
    if not __UPY__:
        pdb("25:please install micropython uasyncio for cpython")
    import asyncio as lib

cycle = 0

loop = lib.get_event_loop()

try:
    schedule = __import__('micropython').schedule
except:
    schedule = False
    pdb("36: micropython.schedule not available")

#=============================================================
# overlay loop (may have been used for console bootstrap ) with a live one
#def reset():
#    global loop
#    if loop.is_closed():
#        pdb('22 : reopening aio loop')
#        lib.set_event_loop(lib.new_event_loop())
#        loop = lib.get_event_loop()
#    else:
#        pdb('26 : aio loop is still open ?')

def task(t, *argv, **kw):
    global loop, pstab
    try:
        name = t.__name__
        pdb("planned", name)
    except:
        pdb("48: MICROPY_PY_FUNCTION_ATTRS=1 better", id(t),t)
        name = id(t)
    pstab.setdefault( name , [] )
    pstab[name].append( t(*argv, **kw) )
    loop.create_task( pstab[name][-1] )


def tasks(*argv,**kw):
    for t in argv:
        task(t,**kw)
    return pstab

async def idle():
    await asleep_ms(1)

#fake run as main
def load(src):
    with open(src,'rb') as f:
        g=globals()
        sv=g['__name__']
        g['__name__']='__main__'
        exec( f.read().decode() , g,g)
        g['__name__']=sv
    use.gc()





if use.board or schedule:
    def step(*argv,**kw):
        global loop, paused, cycle, schedule, failures
        loop.call_soon(loop.stop)
        try:
            loop.run_forever()
        except KeyboardInterrupt:
            paused = True
            pdb('\r\n','resume','restarts AIO loop')

        except Exception as e:
            failures+=1
            pdb('aio broke #',failures,'at',cycle)
            sys.print_exception(e,sys.stderr)

        finally:
            if use.lives:
                if paused is True:
                    if schedule:
                        pdb('42: aio paused', cycle)
                        #allow resuming
                        paused = False
                else:
                    #CRITICAL ? Time.sleep(.0001)
                    cycle+=1
                    schedule(step, 1)
            else:
                pdb('42: aio stopped', cycle)

    def run(*argv):
        global paused, schedule
        for t in argv:
            create_task(t)

        if paused is unset:
            paused = False
            schedule(step, 1)



elif __UPY__:
    print('124: run N/I, WASM using run_once+io.step')
    # on emscripten browser runs the loop both for IO and tasks
    def step(*argv,**kw):
        global loop, paused, cycle, schedule, failures
        try:
            # FIXME: pause and buffer filling up ?
            aio.io.step(*argv)
            if use.lives:
                if paused is not True:
                    loop.run_once()
        except KeyboardInterrupt:
            paused = True
            pdb('\r\n','resume','restarts AIO loop')

        except Exception as e:
            failures+=1
            paused = True
            pdb('aio broke #',failures,'at',cycle)
            sys.print_exception(e,sys.stderr)

        finally:
            if use.lives:
                pass
            else:
                pdb('163: aio stopped', cycle)


else:
    if sys.args.inspect:
        print('PyOS_InputHook')
    else:
        print('asyncio ptpython ?')

#close = loop.close
#create_task = loop.create_task

asleep = lib.sleep


if __UPY__:
    asleep_ms = lib.sleep_ms
    builtins.asyncio = lib
    use.gc()
    start = lib.start
else:
    async def asleep_ms(ms=0):
        await lib.sleep(float(ms)/1000)



__ALL__ = ["lib", "start", "io", "loop", "load", "close", "paused", "step", "run", "asleep", "task", "asleep_ms", "schedule"]


#
